// SPDX-License-Identifier: GPL-2.0-only
/*
 * Unified UUID/GUID definition
 *
 * Copyright (C) 2009, 2016 Intel Corp.
 *	Huang Ying <ying.huang@intel.com>
 */

#include <stdint.h>
#include <lib/uuid.h>
#include <stdbool.h>


const guid_t guid_null;
const uuid_t uuid_null;


const uint8_t guid_index[16] = {3,2,1,0,5,4,7,6,8,9,10,11,12,13,14,15};
const uint8_t uuid_index[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};


/**
 * @brief convert hex digit to binary
 * @param ch: hex digit
 * @return binary value of the hex digit
 */
static int hex_to_bin(unsigned char ch)
{
	unsigned char cu = ch & 0xdf;
	return -1 +
		((ch - '0' +  1) & (unsigned)((ch - '9' - 1) & ('0' - 1 - ch)) >> 8) +
		((cu - 'A' + 11) & (unsigned)((cu - 'F' - 1) & ('A' - 1 - cu)) >> 8);
}


/**
 * generate_random_uuid - generate a random UUID
 * @uuid: where to put the generated UUID
 *
 * Random UUID interface
 *
 * Used to create a Boot ID or a filesystem UUID/GUID, but can be
 * useful for other kernel drivers.
 */
void generate_random_uuid(unsigned char uuid[16])
{
    //get_random_bytes(uuid, 16);
    /* Set UUID version to 4 --- truly random generation */
    uuid[6] = (uuid[6] & 0x0F) | 0x40;
    /* Set the UUID variant to DCE */
    uuid[8] = (uuid[8] & 0x3F) | 0x80;
}


/**
 * @brief generate a random GUID
 * @guid: where to put the generated GUID
 * @return: none
 * @note: GUID is a 128-bit value, which is represented as a 16-byte array.
 *        the version is 4, and DCE is the variant.
 */
void generate_random_guid(unsigned char guid[16])
{
    //get_random_bytes(guid, 16);
    /* Set GUID version to 4 --- truly random generation */
    guid[7] = (guid[7] & 0x0F) | 0x40;
    /* Set the GUID variant to DCE */
    guid[8] = (guid[8] & 0x3F) | 0x80;
}


/**
 * @brief generate a random UUID
 * @param b: where to put the generated UUID
 * @return: none
 * @note: UUID is a 128-bit value, which is represented as a 16-byte array.
 */
static void __uuid_gen_common(uint8_t b[16])
{
    //get_random_bytes(b, 16);
    /* reversion 0b10 */
    b[8] = (b[8] & 0x3F) | 0x80;
}


/**
 * @brief generate a random GUID
 * @param lu: where to put the generated GUID
 * @return: none
 * @note: GUID is a 128-bit value, which is represented as a 16-byte array.
 *        the version is 4.
 */
void guid_gen(guid_t *lu)
{
    __uuid_gen_common(lu->blob);
    /* version 4 : random generation */
    lu->blob[7] = (lu->blob[7] & 0x0F) | 0x40;
}


/**
 * @brief generate a random UUID
 * @param bu: where to put the generated UUID
 * @return: none
 * @note: UUID is a 128-bit value, which is represented as a 16-byte array.
 */
void uuid_gen(uuid_t *bu)
{
    __uuid_gen_common(bu->blob);
    /* version 4 : random generation */
    bu->blob[6] = (bu->blob[6] & 0x0F) | 0x40;
}


/**
 * uuid_is_valid - checks if a UUID string is valid
 * @uuid:	UUID string to check
 *
 * Description:
 * It checks if the UUID string is following the format:
 *	xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
 *
 * where x is a hex digit.
 *
 * Return: true if input is valid UUID string.
 */
bool uuid_is_valid(const char *uuid)
{
    unsigned int i;

    for (i = 0; i < UUID_STRING_LEN; i++) {
        if (i == 8 || i == 13 || i == 18 || i == 23) {
            if (uuid[i] != '-')
                return false;
        } else if (!isxdigit(uuid[i])) {
            return false;
        }
    }

    return true;
}


static int __uuid_parse(const char *uuid, uint8_t b[16], const uint8_t ei[16])
{
    static const uint8_t si[16] = {0,2,4,6,9,11,14,16,19,21,24,26,28,30,32,34};
    unsigned int i;

    if (!uuid_is_valid(uuid))
        return -1;

    for (i = 0; i < 16; i++) {
        int hi = hex_to_bin(uuid[si[i] + 0]);
        int lo = hex_to_bin(uuid[si[i] + 1]);

        b[ei[i]] = (hi << 4) | lo;
    }

    return 0;
}


/**
 * @brief parse a UUID string to a GUID
 * @param uuid:	UUID string to parse
 * @param u:	where to put the parsed GUID
 * @return: 0 if success, -1 if failed
 */
int guid_parse(const char *uuid, guid_t *u)
{
    return __uuid_parse(uuid, u->blob, guid_index);
}


/**
 * @brief parse a UUID string to a UUID
 * @param uuid:	UUID string to parse
 * @param u:	where to put the parsed UUID
 * @return: 0 if success, -1 if failed
 */
int uuid_parse(const char *uuid, uuid_t *u)
{
    return __uuid_parse(uuid, u->blob, uuid_index);
}
